/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frreport_convert.c                                 */
/*  NOTE      = 上报数据转换                                       */
/*  DATE      = 2014/11/26 guojq                                   */
/*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "frcomm.h"
#include "frmem.h"
#include "frlist.h"

#include "conntrack.h"
#include "module.h"
#include "frame_params.h"
#include "frct_mng.h"
#include "frreport_mng.h"

#include "apm.pb-c.h"

#define REPORT_MAC_MAX   50

/*******************************************************************************
*  FUNC     :  释放pbl4
*  ARGS     :  pp_pbl4    L4层信息
*  RTN      :
*  NOTE     :  *pp_pbl4 设为NULL
*******************************************************************************/
static void __free_pbl4(PbL4 **pp_pbl4)
{
    PbL4 *p_pbl4_tmp = *pp_pbl4;
    if (p_pbl4_tmp)
    {
        if (p_pbl4_tmp->src_mac)
            frfree(p_pbl4_tmp->src_mac);
        frfree(p_pbl4_tmp);
        *pp_pbl4 = NULL;
    }
    return;
}

/*******************************************************************************
*  FUNC     :  释放conn
*  ARGS     :  p_connection   conn信息
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
static void __free_conn(PbConnection *p_connection)
{
    if (p_connection)
    {
        if (p_connection->conn_id)
            frfree(p_connection->conn_id);
        __free_pbl4(&p_connection->l4_data);
        if (p_connection->event_timestamp)
            frfree(p_connection->event_timestamp);
        frfree(p_connection);
    }
    return;
}

/*******************************************************************************
*  FUNC     :  释放pbfield
*  ARGS     :  pp_field   如Oracle登录时的SID、客户端程序名等
*  RTN      :  
*  NOTE     :  *pp_field 设为NULL
*******************************************************************************/
static void __free_pbfield(PbField **pp_field)
{
    PbField *p_field_tmp = NULL;
    
    if (pp_field == NULL || *pp_field == NULL)
        return;
        
    p_field_tmp = *pp_field;
    
    if (p_field_tmp->field_name)
        frfree(p_field_tmp->field_name);
    if (p_field_tmp->field_value)
        frfree(p_field_tmp->field_value);

    frfree(p_field_tmp);
    //*pp_field = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  释放pbfield数组
*  ARGS     :  pp_field         数组头
*           :  i_field_num      数组个数
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
static void __free_pbfield_list(PbField **pp_field, int i_field_num)
{
    if (pp_field && i_field_num != 0)
    {
        int i_loop = 0;
        
        for(i_loop=0;i_loop<i_field_num;i_loop++)
        {
            PbField *p_field_tmp = NULL;
            
            p_field_tmp = pp_field[i_loop];
            __free_pbfield(&p_field_tmp);
        }
        frfree(pp_field);
    }
    return;
}

/*******************************************************************************
*  FUNC     :  释放session
*  ARGS     :  p_session    session信息
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
static void __free_session(PbSession *p_session)
{
    if (p_session)
    {
        if (p_session->session_id)
            frfree(p_session->session_id);
        if (p_session->conn_id)
            frfree(p_session->conn_id);
        if (p_session->username)
            frfree(p_session->username);
        if (p_session->event_timestamp)
            frfree(p_session->event_timestamp);
            
        __free_pbl4(&p_session->l4_data);
        
        __free_pbfield_list(p_session->session_data, p_session->n_session_data);
        frfree(p_session);
    }
    return;
}

/*******************************************************************************
*  FUNC     :  释放L7层协议
*  ARGS     :  pp_pbl7_node     L7层协议
*  RTN      :
*  NOTE     :  *pp_pbl7_node 设为NULL
*******************************************************************************/
static void __free_pbl7(PbL7 **pp_pbl7_node)
{
    PbL7 *p_pbl7_tmp = NULL;
    
    if (pp_pbl7_node == NULL || *pp_pbl7_node == NULL)
        return;
    
    p_pbl7_tmp = *pp_pbl7_node;
    if (p_pbl7_tmp)
    {
        if (p_pbl7_tmp->l7_protoname)
            frfree(p_pbl7_tmp->l7_protoname);
        if (p_pbl7_tmp->response_codestring)
            frfree(p_pbl7_tmp->response_codestring);
        if (p_pbl7_tmp->transaction_title)
            frfree(p_pbl7_tmp->transaction_title);
        if (p_pbl7_tmp->server_name)
            frfree(p_pbl7_tmp->server_name);
        if (p_pbl7_tmp->xml_fields)
            frfree(p_pbl7_tmp->xml_fields);
            
        __free_pbfield_list(p_pbl7_tmp->request_fields, p_pbl7_tmp->n_request_fields);
        p_pbl7_tmp->request_fields = NULL;
        __free_pbfield_list(p_pbl7_tmp->response_fields, p_pbl7_tmp->n_response_fields);
        p_pbl7_tmp->response_fields = NULL;
    }
    frfree(p_pbl7_tmp);
    *pp_pbl7_node = NULL;
    
    return;
}

/*******************************************************************************
*  FUNC     :  释放关联链路信息
*  ARGS     :  p_conn_expect    关联链路信息
*  RTN      :
*  NOTE     :  
*******************************************************************************/
static void __free_conn_expect(PbConnectionExpect *p_conn_expect)
{
    if (p_conn_expect == NULL)
        return;
    
    if (p_conn_expect->event_timestamp)
        frfree(p_conn_expect->event_timestamp);

    if (p_conn_expect->l4_data_original)
        __free_pbl4(&p_conn_expect->l4_data_original);

    frfree(p_conn_expect);
    
    return;
}

/*******************************************************************************
*  FUNC     :  释放L7层协议数组
*  ARGS     :  pp_pbl7       L7层协议数组头
*           :  i_pbl7_num    数组个数
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
static void __free_pbl7_list(PbL7 **pp_pbl7, int i_pbl7_num)
{
    if (pp_pbl7 && i_pbl7_num)
    {
        int i_loop = 0;
        
        for(i_loop=0;i_loop<i_pbl7_num;i_loop++)
        {
            PbL7 *p_pbl7_tmp = NULL;
            
            p_pbl7_tmp = pp_pbl7[i_loop];
            __free_pbl7(&p_pbl7_tmp);
        }
        frfree(pp_pbl7);
    }
    return;
}

/*******************************************************************************
*  FUNC     :  释放L7层数据
*  ARGS     :  p_pbl7data     L7层相关数据
*  RTN      :
*  NOTE     :  
*******************************************************************************/
static void __free_l7data(PbL7Data *p_pbl7data)
{
    if (p_pbl7data)
    {
        if (p_pbl7data->conn_id)
            frfree(p_pbl7data->conn_id);
        if (p_pbl7data->session_id)
            frfree(p_pbl7data->session_id);
        if (p_pbl7data->transaction_code)
            frfree(p_pbl7data->transaction_code);
        if (p_pbl7data->transaction_title)
            frfree(p_pbl7data->transaction_title);
        if (p_pbl7data->response_codestring)
            frfree(p_pbl7data->response_codestring);
            
        if (p_pbl7data->request_timestamp)
            frfree(p_pbl7data->request_timestamp);
        if (p_pbl7data->response_timestamp_firstbyte)
            frfree(p_pbl7data->response_timestamp_firstbyte);
        if (p_pbl7data->response_timestamp_all)
            frfree(p_pbl7data->response_timestamp_all);
        
        __free_pbl4(&p_pbl7data->l4_data);
        __free_pbl7_list(p_pbl7data->l7_list, p_pbl7data->n_l7_list);
        frfree(p_pbl7data);
    }
    return;
}

/*******************************************************************************
*  FUNC     :  数据格式化
*  ARGS     :  p_pbdata         需要格式化的数据
*           :  pp_data          格式化后的数据
*           :  p_ui_out         格式化后数据长度
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  pp_data需要外面释放内存
*******************************************************************************/
static int __pbdata_do_pack(PbData *p_pbdata, char **pp_data, unsigned int *p_ui_out)
{
    unsigned int ui_len = 0;
    char *p_out = NULL;
    
    if (p_pbdata == NULL)
        return FR_FAIL;
    
    ui_len = pb_data__get_packed_size(p_pbdata);
    if(ui_len <= 0)
        return FR_FAIL;
    p_out = frmalloc(ui_len + 1);
    if (p_out == NULL)
        return FR_FAIL;
    
    pb_data__pack(p_pbdata, p_out);
    *p_ui_out = ui_len;
    *pp_data = p_out;
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  设置需要格式化的时间信息
*  ARGS     :  l_tv_sec         秒数
*           :  l_tv_usec        微秒数
*           :  pp_datatime      目标PbDateTime结构体
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  pp_datatime需要外面释放内存
*******************************************************************************/
static int __set_datatime(long l_tv_sec, long l_tv_usec, PbDateTime **pp_datatime)
{
    PbDateTime *p_datatime_tmp = NULL;
    
    p_datatime_tmp = frmalloc(sizeof(PbDateTime));
    if (p_datatime_tmp == NULL)
        return FR_FAIL;
    
    memset(p_datatime_tmp, 0x00, sizeof(PbDateTime));
    
    pb_date_time__init(p_datatime_tmp);
    p_datatime_tmp->sec = l_tv_sec;
    p_datatime_tmp->usec = l_tv_usec;
    
    *pp_datatime = p_datatime_tmp;
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  设置PbL4格式化数据
*  ARGS     :  p_mac            mac地址
*           :  i_mac_len        mac地址长度
*           :  ip_proto         协议类型 6(IPPROTO_TCP) / 17(IPPROTO_UDP)
*           :  src_ip           源ip
*           :  src_port         源端口
*           :  dst_ip           目的ip
*           :  dst_port         目的端口
*           :  pp_st_pbl4       设置完成后PbL4结构体
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  pp_st_pbl4需要外面释放内存
*******************************************************************************/
static int __set_pbl4(char *p_mac, int i_mac_len, u_short ip_proto, u_int src_ip, u_short src_port
                    , u_int dst_ip, u_short dst_port, PbL4 **pp_st_pbl4)
{
    PbL4 *p_pbl4_tmp = NULL;
    
    p_pbl4_tmp = frmalloc(sizeof(PbL4));
    if (p_pbl4_tmp == NULL)
        return FR_FAIL;
    
    memset(p_pbl4_tmp, 0x00, sizeof(PbL4));
    
    pb_l4__init(p_pbl4_tmp);
    
    p_pbl4_tmp->src_mac = frmalloc(REPORT_MAC_MAX);
    if (p_pbl4_tmp->src_mac == NULL)
        goto err;
    
    snprintf(p_pbl4_tmp->src_mac, REPORT_MAC_MAX, "%02x:%02x:%02x:%02x:%02x:%02x"
            , FRMAC_ARG(p_mac));
    
    //printf("__set_pbl4 "FRMAC_FMT ", %d\n", p_mac[0], p_mac[1], p_mac[2], p_mac[3], p_mac[4], p_mac[5],i_mac_len);
    
    p_pbl4_tmp->proto = ip_proto;
    p_pbl4_tmp->src_ip = src_ip;
    p_pbl4_tmp->src_port = src_port;
    p_pbl4_tmp->dst_ip = dst_ip;
    p_pbl4_tmp->dst_port = dst_port;
    
    *pp_st_pbl4 = p_pbl4_tmp;
    
    return FR_SUCC;
err:
    if (p_pbl4_tmp)
        __free_pbl4(&p_pbl4_tmp);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  转换Connection的内容
*  ARGS     :  p_st_report_data     转换前的数据结构体
*           :  p_st_pbdata          转换后的数据结构体
*           :  pp_data_out          转换后的内容
*           :  p_ui_data_len        转换后的内容的长度
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  pp_data_out需要外面释放内存
*******************************************************************************/
static int __conn_format(Frreport_data *p_st_report_data
                       , PbData *p_st_pbdata
                       , char **pp_data_out
                       , unsigned int *p_ui_data_len)
{
    PbConnection *p_connection = NULL;
    Frreport_conn *p_report_conn = &p_st_report_data->un_data.st_conn;
    
    p_connection = frmalloc(sizeof(PbConnection));
    if (p_connection == NULL)
        return FR_FAIL;
    
    memset(p_connection, 0x00, sizeof(PbConnection));
    
    pb_connection__init(p_connection);
    
    //设置conn_id
    if ((p_connection->conn_id = frmemdup(p_report_conn->arr_connection_id, sizeof(p_report_conn->arr_connection_id))) == NULL)
        goto err;
    
    //设置PbL4
    if (__set_pbl4(p_report_conn->src_mac, APM_MAC_SIZE, p_report_conn->ip_proto
      , p_report_conn->src_ip, p_report_conn->src_port, p_report_conn->dst_ip, p_report_conn->dst_port, &p_connection->l4_data) != FR_SUCC)
        goto err;
        
    //设置event
    p_connection->event = p_report_conn->i_event;
    
    //设置event时间
    if (__set_datatime(p_report_conn->st_timestamp.tv_sec, p_report_conn->st_timestamp.tv_usec, &p_connection->event_timestamp) != FR_SUCC)
        goto err;
    
    p_st_pbdata->data_type = PB_DATA__DATA_TYPE__CONNECTION_DATA;
    p_st_pbdata->connection = p_connection;
    
    //做protobuf-c pack
    if (__pbdata_do_pack(p_st_pbdata, pp_data_out, p_ui_data_len) != FR_SUCC)
        goto err;
    
    __free_conn(p_connection);
    
    return FR_SUCC;
err:
    __free_conn(p_connection);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  设置PbField格式化数据
*  ARGS     :  p_report_field       转换前的FRdata_field
*           :  pp_out_field         转换后的数据结构体
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  pp_out_field需要外面释放内存
*******************************************************************************/
static int __set_pbfield(Frdata_field *p_report_field, PbField **pp_out_field)
{
    PbField *p_field_tmp = NULL;

    if (p_report_field == NULL)
        return FR_FAIL;

    p_field_tmp = frmalloc(sizeof(PbField));
    if (p_field_tmp == NULL)
        return FR_FAIL;
        
    memset(p_field_tmp, 0x00, sizeof(PbField));
    
    pb_field__init(p_field_tmp);
    //field_name
    if (p_report_field->p_field_name)
    {
        if ((p_field_tmp->field_name = frstrdup(p_report_field->p_field_name)) == NULL)
            goto err;
    }
    
    //field_type
    p_field_tmp->field_type = p_report_field->em_data_type;
    p_field_tmp->field_index = p_report_field->i_field_index;

    if (p_report_field->p_field_value)
    {
        if ((p_field_tmp->field_value = frstrdup(p_report_field->p_field_value)) == NULL)
            goto err;
    }
    
//    switch (p_report_field->em_data_type)
//    {
//        case FRINT:
//            p_field_tmp->int_value = p_report_field->field_value.i_value;
//            p_field_tmp->has_int_value = 1;
//            break;
//        case FRLONG:
//            p_field_tmp->long_value = p_report_field->field_value.ll_value;
//            p_field_tmp->has_long_value = 1;
//            break;
//        case FRFLOAT:
//            p_field_tmp->float_value = p_report_field->field_value.f_value;
//            p_field_tmp->has_float_value = 1;
//            break;
//        case FRDOUBLE:
//            p_field_tmp->double_value = p_report_field->field_value.d_value;
//            p_field_tmp->has_double_value = 1;
//            break;
//        case FRSTRING:
//            if (p_report_field->field_value.p_value)
//            {
//                if ((p_field_tmp->string_value = frstrdup(p_report_field->field_value.p_value)) == NULL)
//                    goto err;
//                p_field_tmp->has_blob_value = 1;
//            }
//            break;
//        case FRTIME:
//            p_field_tmp->datetime_value = p_report_field->field_value.ll_time_value;
//            p_field_tmp->has_datetime_value = 1;
//            break;
//        case FRCLOB:
//        case FRBLOB:
//            if ((p_field_tmp->blob_value.data = frmemdup(p_report_field->field_value.p_st_value->p_data, p_report_field->field_value.p_st_value->ui_len)) == NULL)
//                goto err;
//            p_field_tmp->blob_value.len = p_report_field->field_value.p_st_value->ui_len;
//            break;
//        default:
//            goto err;
//    }
    *pp_out_field = p_field_tmp;
    
    return FR_SUCC;
err:
    __free_pbfield(&p_field_tmp);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  设置FRdata_field格式化数据
*  ARGS     :  p_lst_frdata_header      转换前header节点
*           :  ppp_out_field            转换后的PbField数据结构体
*           :  p_i_field_num            转换后的数据个数
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  ppp_out_field需要外面释放内存
*******************************************************************************/
static int __set_frdata_field_list(Frlist_header *p_lst_frdata_header, PbField ***ppp_out_field, int *p_i_field_num)
{
    PbField **pp_field = NULL;
    Frlist_node *p_list_node = NULL;
    Frdata_field *p_report_list = NULL;
    int i_list_num = 0;
    int i_loop = 0;
    
    i_list_num = frlist_size(p_lst_frdata_header);
    
    if (i_list_num == 0)
        return FR_SUCC;
    
    pp_field = frmalloc(sizeof(PbField *) * i_list_num);
    if (pp_field == NULL)
        return FR_FAIL;
    
    memset(pp_field, 0x00, sizeof(PbField *) * i_list_num);
    
    //report信息链表的头节点
    p_list_node = FRLIST_FIRST_NODE(p_lst_frdata_header);
    
    //遍历report信息，把report信息设置到对应的PbField结构体中
    for (i_loop=0;i_loop<i_list_num && p_list_node;i_loop++)
    {
        PbField *p_field_tmp = NULL;
        
        p_report_list = (Frdata_field *)FRLIST_GET_NODE_DATA(p_list_node);
        
        if (__set_pbfield(p_report_list, &p_field_tmp) != FR_SUCC)
            goto err;
        
        pp_field[i_loop] = p_field_tmp;
        p_list_node = FRLIST_NEXT_NODE(p_list_node);
    }
    *ppp_out_field = pp_field;
    *p_i_field_num = i_list_num;
    
    return FR_SUCC;
err:
    __free_pbfield_list(pp_field, i_list_num);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  转换session的内容
*  ARGS     :  p_st_report_data     转换前的数据结构体
*           :  p_st_pbdata          转换后的数据结构体
*           :  pp_data_out          转换后的内容
*           :  p_ui_data_len        转换后的内容的长度
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  pp_data_out需要外面释放内存
*******************************************************************************/
static int __session_format(Frreport_data *p_st_report_data
                          , PbData *p_st_pbdata
                          , char **pp_data_out
                          , unsigned int *p_ui_data_len)
{
    PbSession *p_session = NULL;
    Frreport_session *p_report_session = &p_st_report_data->un_data.st_session;
    PbField **pp_field = NULL;
    int i_pbfield_list_num = 0;
    
    p_session = frmalloc(sizeof(PbSession));
    if (p_session == NULL)
        return FR_FAIL;
    
    memset(p_session, 0x00, sizeof(PbSession));
    
    pb_session__init(p_session);
    
    //设置session_id
    if ((p_session->session_id = frmemdup(p_report_session->arr_session_id, sizeof(p_report_session->arr_session_id))) == NULL)
        goto err;
    
    //设置conn_id
    if ((p_session->conn_id = frmemdup(p_report_session->arr_connection_id, sizeof(p_report_session->arr_connection_id))) == NULL)
        goto err;
    
    //设置PbL4
    if (__set_pbl4(p_report_session->src_mac, APM_MAC_SIZE, p_report_session->ip_proto
      , p_report_session->src_ip, p_report_session->src_port, p_report_session->dst_ip, p_report_session->dst_port, &p_session->l4_data) != FR_SUCC)
        goto err;
        
    //设置username
    if (p_report_session->p_username)
    {
        if ((p_session->username = frstrdup(p_report_session->p_username)) == NULL)
            goto err;
    }
        
    p_session->event = p_report_session->i_status;
    
    //设置event时间
    if (__set_datatime(p_report_session->st_timestamp.tv_sec, p_report_session->st_timestamp.tv_usec, &p_session->event_timestamp) != FR_SUCC)
        goto err;
    
    //设置session data
    if (__set_frdata_field_list(p_report_session->p_st_lst_session_data, &pp_field, &i_pbfield_list_num) != FR_SUCC)
        goto err;
    
    p_session->session_data = pp_field;
    p_session->n_session_data = i_pbfield_list_num;
    
    p_st_pbdata->data_type = PB_DATA__DATA_TYPE__SESSION_DATA;
    p_st_pbdata->session = p_session;
    
    //做protobuf-c pack
    if (__pbdata_do_pack(p_st_pbdata, pp_data_out, p_ui_data_len) != FR_SUCC)
        goto err;
    
    __free_session(p_session);
    
    return FR_SUCC;
err:
    __free_session(p_session);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  设置PbL7链表格式化数据
*  ARGS     :  p_lst_l7data_header      转换前header节点
*           :  p_l7data                 转换后的PbField数据结构体
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  成功时内容放在PbL7Data的l7_list中，需要外面释放
*******************************************************************************/
static int __set_l7data_list(Frlist_header *p_lst_l7data_header, PbL7Data *p_l7data)
{
    PbL7 **pp_l7data = NULL;
    Frlist_node *p_list_node = NULL;
    FRl7data_field *p_field_tmp = NULL;
    PbField **pp_pbfield_request = NULL;
    PbField **pp_pbfield_response = NULL;
    int i_l7data_list_num = 0;
    int i_pbfield_request_num = 0;
    int i_pbfield_response_num = 0;
    int i_loop = 0;
    
    //取list的总长度
    i_l7data_list_num = frlist_size(p_lst_l7data_header);
    
    if (i_l7data_list_num == 0)
        return FR_SUCC;
    
    pp_l7data = frmalloc(sizeof(PbL7) * i_l7data_list_num);
    if (pp_l7data == NULL)
        return FR_FAIL;
    
    memset(pp_l7data, 0x00, sizeof(PbL7) * i_l7data_list_num);
    
    //取report的头节点
    p_list_node = FRLIST_FIRST_NODE(p_lst_l7data_header);
    
    for (i_loop=0;i_loop<i_l7data_list_num && p_list_node;i_loop++)
    {
        PbL7 *p_pbl7_tmp = NULL;
        
        //当前report节点FRl7data_field结构体
        p_field_tmp = (FRl7data_field *)FRLIST_GET_NODE_DATA(p_list_node);
        
        p_pbl7_tmp = frmalloc(sizeof(PbL7));
        if (p_pbl7_tmp == NULL)
            goto err;
        
        memset(p_pbl7_tmp, 0x00, sizeof(PbL7));
        
        pb_l7__init(p_pbl7_tmp);
        
        //L7层协议
        p_pbl7_tmp->l7_proto = p_field_tmp->i_l7_proto;
        //L7层协议名
        if (p_field_tmp->p_module_name)
        {
            if ((p_pbl7_tmp->l7_protoname = frstrdup(p_field_tmp->p_module_name)) == NULL)
            {
                frfree(p_pbl7_tmp);
                goto err;
            }
        }
        //最底层L7协议返回码,例如200
        p_pbl7_tmp->response_code = p_field_tmp->l_response_code;
        p_pbl7_tmp->has_response_code = 1;
        //最底层L7协议返回码字符串，例如200 OK
        if (p_field_tmp->p_response_codestring)
        {
            if ((p_pbl7_tmp->response_codestring = frstrdup(p_field_tmp->p_response_codestring)) == NULL)
            {
                frfree(p_pbl7_tmp);
                goto err;
            }
        }
        if (p_field_tmp->p_transaction_title)
        {
            if ((p_pbl7_tmp->transaction_title = frstrdup(p_field_tmp->p_transaction_title)) == NULL)
            {
                frfree(p_pbl7_tmp);
                goto err;
            }
        }
        if (p_field_tmp->p_server_name)
        {
            if ((p_pbl7_tmp->server_name = frstrdup(p_field_tmp->p_server_name)) == NULL)
            {
                frfree(p_pbl7_tmp);
                goto err;
            }
        }
        p_pbl7_tmp->batch_count = p_field_tmp->i_batch_count;
        if (p_field_tmp->p_xml_fields)
        {
            if ((p_pbl7_tmp->xml_fields = frstrdup(p_field_tmp->p_xml_fields)) == NULL)
            {
                frfree(p_pbl7_tmp);
                goto err;
            }
        }
        
        //请求的所有参数列表，字段名双方约定
        if (__set_frdata_field_list(p_field_tmp->p_st_lst_request_data, &pp_pbfield_request, &i_pbfield_request_num) != FR_SUCC)
            goto err;
        
        p_pbl7_tmp->request_fields = pp_pbfield_request;
        p_pbl7_tmp->n_request_fields = i_pbfield_request_num;

        //应答结果列表，字段名双方约定
        if (__set_frdata_field_list(p_field_tmp->p_st_lst_response_data, &pp_pbfield_response, &i_pbfield_response_num) != FR_SUCC)
            goto err;
        
        p_pbl7_tmp->response_fields = pp_pbfield_response;
        p_pbl7_tmp->n_response_fields = i_pbfield_response_num;
        
        pp_l7data[i_loop] = p_pbl7_tmp;
        p_list_node = FRLIST_NEXT_NODE(p_list_node);
    }
    p_l7data->l7_list = pp_l7data;
    p_l7data->n_l7_list = i_l7data_list_num;
    
    return FR_SUCC;
err:
    __free_pbl7_list(pp_l7data, i_l7data_list_num);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  转换L7层数据的内容
*  ARGS     :  p_st_report_data     转换前的数据结构体
*           :  p_st_pbdata          转换后的数据结构体
*           :  pp_data_out          转换后的内容
*           :  p_ui_data_len        转换后的内容的长度
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  pp_data_out需要外面释放内存
*******************************************************************************/
static int __l7data_format(Frreport_data *p_st_report_data
                          , PbData *p_st_pbdata
                          , char **pp_data_out
                          , unsigned int *p_ui_data_len)
{
    PbL7Data *p_l7data = NULL;
    Frreport_l7data *p_report_l7data = &p_st_report_data->un_data.st_l7data;
    
    p_l7data = frmalloc(sizeof(PbL7Data));
    if (p_l7data == NULL)
        return FR_FAIL;
    
    memset(p_l7data, 0x00, sizeof(PbL7Data));
    
    pb_l7_data__init(p_l7data);
    
    //设置session_id
    if ((p_l7data->session_id = frmemdup(p_report_l7data->arr_session_id, sizeof(p_report_l7data->arr_session_id))) == NULL)
        goto err;
    
    //设置conn_id
    if ((p_l7data->conn_id = frmemdup(p_report_l7data->arr_connection_id, sizeof(p_report_l7data->arr_connection_id))) == NULL)
        goto err;
    
    //设置L4层信息
    if (__set_pbl4(p_report_l7data->src_mac, APM_MAC_SIZE, p_report_l7data->ip_proto
      , p_report_l7data->src_ip, p_report_l7data->src_port, p_report_l7data->dst_ip
      , p_report_l7data->dst_port, &p_l7data->l4_data) != FR_SUCC)
        goto err;
        
    //请求类型，请求/应答
    if (p_report_l7data->i_use_response == FR_YES)
        p_l7data->data_type = PB_L7_DATA__L7_DATA_TYPE__RESPONSE;
    else
        p_l7data->data_type = PB_L7_DATA__L7_DATA_TYPE__REQUEST;
    
    p_l7data->request_bytes = p_report_l7data->l_request_bytes;
    
    //设置 所有请求数据发送完的时间
    if (__set_datatime(p_report_l7data->st_request_time.tv_sec
                , p_report_l7data->st_request_time.tv_usec, &p_l7data->request_timestamp) != FR_SUCC)
        goto err;
    
    //设置交易码
    if (p_report_l7data->p_transaction_code)
    {
        if ((p_l7data->transaction_code = frstrdup(p_report_l7data->p_transaction_code)) == NULL)
            goto err;
    }
    
    //设置交易名称
    if (p_report_l7data->p_transaction_title)
    {
        if ((p_l7data->transaction_title = frstrdup(p_report_l7data->p_transaction_title)) == NULL)
            goto err;
    }
        
    //设置最底层L7协议返回码,例如200
    p_l7data->response_code = p_report_l7data->l_response_code;
    p_l7data->has_response_code = 1;
    //设置最底层L7协议返回码字符串，例如200 OK
    if (p_report_l7data->p_response_codestring)
    {
        if ((p_l7data->response_codestring = frstrdup(p_report_l7data->p_response_codestring)) == NULL)
            goto err;
    }
    
    //首包时间戳
    if (__set_datatime(p_report_l7data->st_response_time_first_byte.tv_sec
                , p_report_l7data->st_response_time_first_byte.tv_usec, &p_l7data->response_timestamp_firstbyte) != FR_SUCC)
        goto err;
    //应答完成时间戳
    if (__set_datatime(p_report_l7data->st_response_time.tv_sec
                , p_report_l7data->st_response_time.tv_usec, &p_l7data->response_timestamp_all) != FR_SUCC)
        goto err;
    //应答的总字节数
    p_l7data->has_response_bytes = 1;
    p_l7data->response_bytes = p_report_l7data->l_response_bytes;
    //首包时间，是指从请求发起到收到第一个应答包时间，使用微秒表示
    p_l7data->response_time_firstbyte_us = p_report_l7data->ul_response_time_firstbyte_us;
    p_l7data->has_response_time_firstbyte_us = 1;
    //应答时间，是指从请求发起到所有应答结束总花费的时间，使用微秒表示
    p_l7data->response_time_us = p_report_l7data->ul_response_time_us;
    p_l7data->has_response_time_us = 1;
    //0:不期待响应数据,>=1:有response数据
    p_l7data->response_want = p_report_l7data->i_response_required;
    
    if (__set_l7data_list(&p_report_l7data->st_lst_l7data, p_l7data) != FR_SUCC)
        goto err;
    
    p_st_pbdata->data_type = PB_DATA__DATA_TYPE__L7_DATA;
    p_st_pbdata->l7_data = p_l7data;
    
    //做protobuf-c pack
    if (__pbdata_do_pack(p_st_pbdata, pp_data_out, p_ui_data_len) != FR_SUCC)
        goto err;
    
    __free_l7data(p_l7data);
    
    return FR_SUCC;
err:
    __free_l7data(p_l7data);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  转换关联链路的内容
*  ARGS     :  p_st_report_data     转换前的数据结构体
*           :  p_st_pbdata          转换后的数据结构体
*           :  pp_data_out          转换后的内容
*           :  p_ui_data_len        转换后的内容的长度
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  pp_data_out需要外面释放内存
*******************************************************************************/
static int __conn_expect_format(Frreport_data *p_st_report_data
                          , PbData *p_st_pbdata
                          , char **pp_data_out
                          , unsigned int *p_ui_data_len)
{
    PbConnectionExpect *p_conn_expect = NULL;
    Frreport_conn_expect *p_report_conn_expect = &p_st_report_data->un_data.st_conn_expect;
    
    p_conn_expect = frmalloc(sizeof(PbConnectionExpect));
    if (p_conn_expect == NULL)
        return FR_FAIL;
    
    memset(p_conn_expect, 0x00, sizeof(PbConnectionExpect));
    
    pb_connection_expect__init(p_conn_expect);
    
    //重定向的目标IP、端口
    p_conn_expect->redirect_ip = p_report_conn_expect->redirect_ip;
    p_conn_expect->redirect_port = p_report_conn_expect->redirect_port;
    
    //设置PbL4
    if (__set_pbl4(p_report_conn_expect->src_mac, APM_MAC_SIZE, p_report_conn_expect->ip_proto
      , p_report_conn_expect->src_ip, p_report_conn_expect->src_port, p_report_conn_expect->dst_ip, p_report_conn_expect->dst_port, &p_conn_expect->l4_data_original) != FR_SUCC)
        goto err;
    
    //设置 事件发生时间
    if (__set_datatime(p_report_conn_expect->st_timestamp.tv_sec
                , p_report_conn_expect->st_timestamp.tv_usec, &p_conn_expect->event_timestamp) != FR_SUCC)
        goto err;
    
    p_st_pbdata->data_type = PB_DATA__DATA_TYPE__EXPECT_DATA;
    p_st_pbdata->expect_data = p_conn_expect;
    
    //做protobuf-c pack
    if (__pbdata_do_pack(p_st_pbdata, pp_data_out, p_ui_data_len) != FR_SUCC)
        goto err;
    
    __free_conn_expect(p_conn_expect);
    
    return FR_SUCC;
err:
    __free_conn_expect(p_conn_expect);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  转换report数据
*  ARGS     :  p_st_report_data     转换前的数据
*           :  pp_data_out          转换后的内容
*           :  p_ui_data_len        转换后的内容的长度
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :  pp_data_out需要外面释放内存
*******************************************************************************/
int frreport_convert(Frreport_data *p_st_report_data
                   , char **pp_data_out
                   , unsigned int *p_ui_data_len)
{
    PbData st_pbdata;
    
    if (p_st_report_data == NULL || pp_data_out == NULL || p_ui_data_len==NULL)
        return FR_FAIL;
    
    memset(&st_pbdata, 0x00, sizeof(PbData));
    pb_data__init(&st_pbdata);
    
    switch (p_st_report_data->em_data_type)
    {
        case FRREPORT_TYPE_CONN:
            if (__conn_format(p_st_report_data, &st_pbdata, pp_data_out, p_ui_data_len) != FR_SUCC)
                return FR_FAIL;
            break;
        case FRREPORT_TYPE_SESSION:
            if (__session_format(p_st_report_data, &st_pbdata, pp_data_out, p_ui_data_len) != FR_SUCC)
                return FR_FAIL;
            break;
        case FRREPORT_TYPE_DATA:
            if (__l7data_format(p_st_report_data, &st_pbdata, pp_data_out, p_ui_data_len) != FR_SUCC)
                return FR_FAIL;
            break;
        case FRREPORT_TYPE_CONN_EXPECT:
            if (__conn_expect_format(p_st_report_data, &st_pbdata, pp_data_out, p_ui_data_len) != FR_SUCC)
                return FR_FAIL;
            break;
        default:
            return FR_FAIL;
    }
    
    return FR_SUCC;
}
